#encoding:utf-8
'''
FileName:handler.py
Creator:王烨
Date:2010.5.23
'''
from twisted.internet.defer import Deferred
from twisted.protocols.basic import Int32StringReceiver
from twisted.python.failure import Failure
from google.protobuf.message import DecodeError
from rpc_pb2 import *
from controller import Controller
from error import ProtobufError

class Handler(Int32StringReceiver):
    '''实现RPC协议'''
    def __init__(self, services):
        self.__services = services
        
    def connectionMade(self):
        peer = self.transport.getPeer()
        print '{0}:{1} connected'.format(peer.host, peer.port)
        
    def connectionLost(self, reason):
        print 'Connection closed',reason
        
    def stringReceived(self, data):
        '''接收到数据时的回调'''
        try:
            request = Request()
            try:
                print '开始解析RPC请求'
                request.ParseFromString(data)
            except DecodeError:
                raise ProtobufError(BAD_REQUEST_DATA, 'Fail to deserialize RPC request')
            print '验证RPC请求完整性'
            if not request.IsInitialized():
                raise ProtobufError(BAD_REQUEST_PROTOCOL, 'Bad RPC request')
            self.uuid = request.uuid
            
            serviceName = request.serviceName
            print '查找服务名'
            try:
                service = self.__services[serviceName]
            except KeyError:
                raise ProtobufError(SERVICE_NOT_FOUND, 'Fail to find service:{0}'.format(serviceName))
            
            print '查找方法名'
            methodName = request.methodName
            method = service.GetDescriptor().FindMethodByName(methodName)
            if not method:
                raise ProtobufError(METHOD_NOT_FOUND, 'Fail to find method:{0}'.format(methodName))
            
            print '开始检查参数'
            parameters = service.GetRequestClass(method)()
            try:
                parameters.ParseFromString(request.parameters)
            except DecodeError:
                raise ProtobufError(BAD_REQUEST_DATA, 'Fail to deserialize parameters')
            if not parameters.IsInitialized():
                raise ProtobufError(BAD_REQUEST_PROTOCOL, 'Bad RPC request')
            self.controller = Controller()
        
            d = Deferred()
            d.addCallback(self.__serializeResponse)
            d.addCallback(self.__sendResponse)
            d.addErrback(self.__handleError)
            print '开始执行方法'
            service.CallMethod(method, self.controller, parameters, d.callback)
            
        except ProtobufError as err:
            failure = Failure(err)
            self.__handleError(failure)
        except Exception as err:
            failure = Failure(ProtobufError(RPC_ERROR, str(err)))
            self.__handleError(failure)
    
    def __serializeResponse(self, result):
        '''序列化RPC响应'''
        print '开始检查controller'
        #if self.controller.Failed():
            #raise RPCFail(self.controller.ErrorText())
        print '开始序列化RPC响应'
        response = Response()
        response.uuid = self.uuid
        response.result = result.SerializeToString()
        return response.SerializeToString()
    
    def __serializeErrorResponse(self, err):
        '''序列化错误响应'''
        print '处理错误响应'
        response = Response()
        response.uuid = self.uuid
        e = response.error.add()
        e.type = err.type
        e.text = err.text
        return response.SerializeToString()
    
    def __sendResponse(self, serializedResponse):
        '''发送RPC响应'''
        print '开始发送响应'
        self.sendString(serializedResponse)
        
    def __handleError(self, failure):
        '''处理异步回调执行过程中产生的异常'''
        err = failure.value
        if err is ProtobufError and (err.GetType() == BAD_REQUEST_DATA or err.GetType() == BAD_REQUEST_PROTOCOL):
            print failure.getErrorMessage()
            self.transport.loseConnection()
        else:
            print 'Exception:',failure.getErrorMessage()
            print 'Trace:',failure.getTraceback()
            e = Error()
            if err is ProtobufError:
                e.type = err.type
            else:
                e.type = RPC_ERROR
            e.text = failure.getErrorMessage()
            d = Deferred()
            d.addCallback(self.__serializeErrorResponse)
            d.addCallback(self.__sendResponse)
            d.callback(e)